			#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "biblioteca.h"


/**
 * Funcao nexttoken altera o valor da variavel str,
 * que eh passada por referencia. Esta variavel passa 
 * a conter o proximo token encontrado no buffer. Esta
 * funcao retorna um numero inteiro, que serve para
 * especificar o tipo do token obtido. Os codigos de cada
 * tipo de token sao os seguintes:
 * 
 * 1: ";" (token ponto e virgula)
 * 2: Palavra Reservada
 * 3: Variavel
 * 4: Numero (integer ou real)
 * 5: Literal
 * 6: Operador ('+', '-', '/', '*')
 * 7: Numero Integer
 * 8: Numero Real
 * 
*/
int nexttoken(){
    char c;
	char string[50];
    int tipoToken = 0;
    
	while (tipoToken == 0){    
	    
        if (buffer.ind_buffer > 49){            
			encherBuffer();
        }
        
        c = lerChar();
        
        if(c == EOF) break; //fim de arquivo
        
        else if (c == ';'){ //token ;
            strcpy(string, ";");
            tipoToken = 1; 
        }
        
        //se for letra ou começa com _, então é uma variável ou palavra reservada
        else if ((c >= 'A' && c<='Z') || (c >= 'a' && c<='z') || c == '_'){
			//Chamar a rotina que identifica variaveis/palavras reservadas
            buffer.ind_buffer--;
            tipoToken = variavel(string);
            
        }
        else if ((c >='0' && c <= '9') || c == '.'){
            //Chamar a rotina que identifica numeros
            buffer.ind_buffer--;
            AFDNumeros(string);
			tipoToken = 4;
            
        }
        else if (c == '\''){
            literais(string);
			tipoToken = 5;
        }
        else if ((c == '+') || (c == '-') || (c == '*') || (c == '=') || (c == '<') || (c == '>') || (c == ':') || (c == '/')){
            //Chamar o automato que identifica operadores e comparadores e atribuicao
            buffer.ind_buffer--;
            AFDOperadores(string);
			tipoToken = 6;
        }
    }
    strcpy(tokenAtual, string);
    
    //Verificacao se o numero eh inteiro ou real
    if (tipoToken == 4){
            int gamb;
            gamb = strlen(string);
            if ((tokenAtual[gamb-1] == '.') || (strchr(tokenAtual, '.') == NULL)){  //Verificando se existe . no numero, e se existir, se eh o ultimo caractere(sendo assim um inteiro)
                tipoToken = 7;
                if (tokenAtual[gamb-1] == '.'){
                    tokenAtual[gamb-1] = '\0';
                }
            }
            else {
                tipoToken = 8;
            }
    }
    printf("TOKEN ATUAL = %s \n", tokenAtual);
    return tipoToken;
}

//------------------------------------------------------------------------------------------------------------------------------

int checkprogram(){
	int check;
	
	check = strcmp(tokenAtual, "PROGRAM");
	
	if (check == 0)
		return 1; //sucesso, program encontrado :)
	
	return 0; //falha, program nao encontrado :(
}

//-------------------------------------------------------------------------------------------------------------------------------

int checkdeclaracao(){
    char string[50];
    int stop = 0;
    char c;
    int tipoToken = 0;
    tipoToken = nexttoken();
    
    if (strcmp(tokenAtual, "BEGIN") == 0){
        return 2;    //Fim das declaracoes e inicio do bloco. Saira desempilhando todas as chamadas recursivas desta funcao.
    }
    
    
    //Verificacao da variavel
    if (isVariavel(tipoToken)) {   //Verifica se string eh uma variavel        
        //verificacao do separador ':'
        tipoToken = nexttoken();
        if (strcmp(tokenAtual, ":") == 0){  //verifica se o caractere encontrado eh ':', que deve ficar entre a variavel e o seu tipo em uma declaracao
            tipoToken = nexttoken();  //O separador ':' foi encontrado. Prossegue a verificacao do tipo da variavel declarada
        }
        else{
            printf("Erro. O caractere ':' nao foi encontrado apos a variavel \n");
            return 0;   //Codigo de erro. Falta do separador ':'
        }
        
        //Verificacao do tipo da variavel
        if (isPReservada(tipoToken) == 1){    //Verifica se eh uma uma palavra reservada
            if (isTipoVariavel() == 1){   //Verifica se eh um tipo de variavel valido
                tipoToken = nexttoken();  //O tipo foi aceito. Prossegue a verificacao buscando pelo ';'
            }
            else if (strcmp(tokenAtual, "ARRAY") == 0){  //Verifica se eh um ARRAY. Caso positivo, ira verificar a estrutura da declaracao de ARRAY ( [1..5] of tipovariavel)
                char gambs1;
                char gambs2;
                gambs1 = ' ';
                while (gambs1 == ' '){   //Ignora os espacos em branco
                    gambs1 = lerChar();   
                }
                if (gambs1 != '['){   //Verifica o [. Se a condicao for verdadeira, nao encontrou [, e retorna erro
                    printf("Erro. Nao foi encontrado o caractere '[' apos ARRAY \n");
                    return 0;   //Codigo de erro. Falta de [
                }                
                tipoToken = nexttoken();    //Busca pelo primeiro inteiro
                if (isInteger(tipoToken) == 0){   //Verifica se o token atual eh um numero
                    printf("Erro. Nao foi encontrado um numero inteiro como indice inicial do ARRAY \n");
                    return 0;
                }
                //Verificacao do .. para separar o indice inicial do indice final do ARRAY
                buffer.ind_buffer--;
                gambs1 = lerChar();
                gambs2 = lerChar();                
                if ((gambs1 != '.') || (gambs2 != '.')){  //if (strcmp(gambs, "..") != 0)
                    printf("Erro. Nao foi encontrado .. entre os indices do ARRAY \n");
                    return 0;
                } 
                //Busca pelo segundo inteiro
                tipoToken = nexttoken();    
                if (isInteger(tipoToken) == 0){   //Verifica se o token atual eh um numero
                    printf("Erro. Nao foi encontrado um numero inteiro como indice final do ARRAY \n");
                    return 0;
                }
                //Busca pelo caractere ']' para fechar os indices
                gambs1 = ' ';
                while (gambs1 == ' '){   //Ignora os espacos em branco
                    gambs1 = lerChar();   
                }
                if (gambs1 != ']'){   //Verifica o ]. Se a condicao for verdadeira, nao encontrou ], e retorna erro
                    printf("Erro. Nao foi encontrado o caractere ']' apos ARRAY \n");
                    return 0;   //Codigo de erro. Falta de [
                }
                //Buscando pelo token OF
                tipoToken = nexttoken();
                if (strcmp(tokenAtual, "OF") != 0){
                    printf("Erro. Nao foi encontrado o token 'OF' para a definicao do tipo ARRAY \n");
                    return 0;   //Codigo de erro. Falta de token OF
                }
                //Buscando pelo tipo
                tipoToken = nexttoken();                
                if (isTipoVariavel() == 0){     //Verificacao de tipo de variavel valido
                    printf("Erro. Nao foi encontrado um tipo valido para o ARRAY \n");
                    return 0;   //Codigo de erro. Falta de tipo do ARRAY
                }
            }
        }
        else {
            printf("Erro. Nao foi encontrado um tipo valido! \n");
            return 0;   //Codigo de erro. Tipo invalido
        }
        //Verificacao do ';'
        tipoToken = nexttoken();        
        if (isPontovirgula()){  //Verifica se eh ';'
            checkdeclaracao();  //chama a funcao recursivamente
        }
        else if ((strcmp(tokenAtual, "BEGIN") == 0) || (strcmp(tokenAtual, "PROCEDURE") == 0) || (strcmp(tokenAtual, "FUNCTION") == 0)){
            return 2;
        }
        else{
            printf("Erro. Era esperado o caractere ; no final da linha! \n");
            return 0;   //Codigo de erro. Falta de ;
        }
    }
    else{
        printf("Erro. Era esperado uma variavel antes de : \n");
        return 0;   //Codigo de erro. Falta de variavel
    }
    return 1;
}

//------------------------------------------------------------------------------------------------------------------------------

/**
 * A funcao isVariavel verifica se o inteiro tipoToken passado como parametro eh igual a 3,
 * sendo assim uma variavel, de acordo com o codigo de tipos de tokens (codigo 3: variavel).
*/
int isVariavel(int tipoToken){
    if (tipoToken == 3) 
        return 1;   //tipoToken eh uma variavel
    return 0;   //tipoToken nao eh uma variavel
}

//------------------------------------------------------------------------------------------------------------------------------

/**
 * A funcao isPontovirgula verifica se o token atual eh um ponto e virgula, e retorna 1 se verdadeiro, ou 0 se falso 
*/
int isPontovirgula(){
	if (strcmp(tokenAtual, ";") == 0){  //Verifica se eh ';'
		return 1;	//tokenAtual == ;
	}
	return 0;	//tokenAtual != ;
}


//------------------------------------------------------------------------------------------------------------------------------

/**
 * A funcao isPalavraReservada verifica se o inteiro tipoToken passado como parametro eh igual a 2,
 * sendo assim uma palavra reservada, de acordo com o codigo de tipos de tokens (codigo 2: palavra reservada).
*/
int isPReservada(int tipoToken){
    if (tipoToken == 2) 
        return 1;   //tipoToken eh uma palavra reservada
    return 0;   //tipoToken nao eh uma palavra reservada
}

//------------------------------------------------------------------------------------------------------------------------------


/**
 * A funcao isInteger verifica se o inteiro tipoToken passado como parametro eh igual a 4,
 * sendo assim um numero, de acordo com o codigo de tipos de tokens (codigo 4: numero).
*/
int isInteger(int tipoToken){
    if (tipoToken == 7) 
        return 1;   //tipoToken eh um numero inteiro
    return 0;   //tipoToken nao eh um numero inteiro
}

//------------------------------------------------------------------------------------------------------------------------------

/**
 * A funcao isNumero verifica se o inteiro tipoToken passado como parametro eh igual a 7 ou 8,
 * sendo assim um numero, de acordo com o codigo de tipos de tokens (codigo 7: integer  e  codigo 8: real).
*/
int isNumero(int tipoToken){
    if ((tipoToken == 7) || (tipoToken == 8)) 
        return 1;   //tipoToken eh um numero
    return 0;   //tipoToken nao eh um numero
}

//------------------------------------------------------------------------------------------------------------------------------


/**
 * A funcao isLiteral verifica se o inteiro tipoToken passado como parametro eh igual a 5,
 * sendo assim um literal, de acordo com o codigo de tipos de tokens (codigo 5: literal).
*/
int isLiteral(int tipoToken){
    if (tipoToken == 5) 
        return 1;   //tipoToken eh um literal
    return 0;   //tipoToken nao eh um literal
}

//------------------------------------------------------------------------------------------------------------------------------



/**
 * A funcao isTipoVariavel verifica se o inteiro tipoToken passado como parametro eh igual a 2,
 * sendo assim uma palavra reservada, de acordo com o codigo de tipos de tokens (codigo 2: palavra reservada).
*/
int isTipoVariavel(){
    if ((strcmp(tokenAtual, "REAL") == 0) ||
        (strcmp(tokenAtual, "CHAR") == 0) ||
        (strcmp(tokenAtual, "INTEGER") == 0) ||
        (strcmp(tokenAtual, "STRING") == 0) ||
        (strcmp(tokenAtual, "BOOLEAN") == 0)){
        
        return 1;   //Codigo de retorno 1: tipo de variavel valido
    }
    return 0;
}

//-------------------------------------------------------------------------------------------------------------------------------


/**
 * Funcao checkAtribuicao verifica a estrutura da atribuicao de uma variavel e sera chamada sempre que for identificada uma
 * variavel previamente declarada no escopo a qual ela pertence depois de um ';'
 * @return int
 */
int checkAtribuicao(){
    
    int tipoToken;
    
    //o ultimo token lido foi uma variavel, comeca agora a busca pelo sinal de atribuicao ":="
    tipoToken = nexttoken();
    if (strcmp(tokenAtual, ":=") != 0){       //se a condicao for verdadeira, o sinal de atribuicao nao foi encontro
        printf("Erro. O token := nao foi encontrado \n");
        return 0;       //Codigo de erro. := nao encontrado
    }
    
    checkExpressaoAtribuicao();
    
}

//-------------------------------------------------------------------------------------------------------------------------------

/**
 *Funcao checkExpressaoAtribuicao() verifica a estrutura da expressao que vem depois do sinal := em uma atribuicao
 * 
 */
int checkExpressaoAtribuicao(){
    int tipoToken;
    int flag = 0;        //Sera usado para identificar que o proximo token devera ser ;
    int indFunction;
    
    
    //o ultimo caractere lido foi := e comeca agora a busca pelas variaveis ou valores
    tipoToken = nexttoken();
    if (isNumero(tipoToken) == 1){      //Verifica se o token atual eh um numero
        //foi encontrado um numero
        if (recursaoExpressao() != 1){
            printf("Erro. Expressao incorreta. \n");
            return 0;
        }
        return 1;
    }
    else if (isLiteral(tipoToken) == 1){      //Verifica se o token atual eh um literal
        //foi encontrado um literal
        flag = 1;        //O proximo caractere devera ser ;
        tipoToken = nexttoken();
        if (strcmp(tokenAtual, ";") != 0){
			printf("Erro. O token ; era esperado e nao foi encontrado. \n");
			return 1;
		}
    }
    
    //Fazer a verificacao de function    
    else if (isVariavel(tipoToken) == 1){
        
        //Checkagem da chamada de uma funcao
        indFunction = isFunction();
        if (indFunction > -1){  
            if (checkParametros(indFunction) != 1){
                printf("Erro. Passagem de parametros invalida. \n");
                return 0;
            }
        }
        else {
            if (recursaoExpressao() != 1){
                printf("Erro. Expressao incorreta. \n");
                return 0;
            }
        }
    }
}

//-------------------------------------------------------------------------------------------------------------------------------

/**
 * Funcao recursaoExpressao() verifica a estrutura da recursao de uma expressao. Esta eh uma funcao recursiva, e o primeiro
 * token encontrado por esta funcao devera ser um operador ('+', '-', '*', '/'). em seguida, a funcao devera encontrar um
 * numero ou uma variavel, e chama-la recursivamente, ate que seja encontrado o token ;
 * Retorna 1 se nao ocorrer nenhum erro, ou 0 se encontrar erros
 * 
 */
int recursaoExpressao(){
    int tipoToken;
    int retorno;
    
    //O ultimo token encontrado foi um numero ou uma variavel. O proximo token devera ser um operador matematico ou ; para sair da funcao
    tipoToken = nexttoken();
    //Verificacao da condicao de saida da funcao por ;
    if (strcmp(tokenAtual, ";") == 0){
        //Saida esperada da funcao
        return 1;
    }    
    else if ((strcmp(tokenAtual, "+") == 0) || (strcmp(tokenAtual, "-") == 0) || (strcmp(tokenAtual, "*") == 0) || (strcmp(tokenAtual, "/") == 0)){
        //encontrou um operador matematico
    }
    else {
        printf("Erro. Falta de operador matematico na expressao. \n");
        return 0;
    }
    
    //Verificacao do proximo membro da expressao
    tipoToken = nexttoken();
    if ((isNumero(tipoToken) == 1) || (isVariavel(tipoToken) == 1)){
        //Chamada recursiva da funcao
        retorno = recursaoExpressao();
        return retorno;
    }

}











//-------------------------------------------------------------------------------------------------------------------------------
/**
 * Funcao checkParametros() verifica se o numero de parametros em uma chamada de funcao eh igual ao numero de parametros
 * da funcao presente na tabela de funcoes e procedimentos
 * 
 * retorna 1 se verdadeiro, ou 0 se falso
 */
int checkParametros(int indFuction){
    int i;
    int tipoToken;
    char c;
    int gambs = 0;
    
    c = ' ';
    while (c == ' '){
        c = lerChar();
    }
    if (c != '('){
        printf("Erro. o token ( era esperado na passagem de parametros. \n");
        return 0;
    }
    for (i = 0; i < tableFuncProc[indFuction].contParametros; i++){
        //Considerando o fechamento de parenteses
        c = ' ';
        while (c == ' '){
            c = lerChar();
        }
        if (c == ')'){
            break;
        }
        buffer.ind_buffer--;          
        //Considerando a virgula
        c = ' ';
        while (c == ' '){
            c = lerChar();
        }
        if (c != ','){
            buffer.ind_buffer--;          
        }
        
        //Considerando um token valido para a analise
        tipoToken = nexttoken();
        if ((isNumero(tipoToken)) || (isLiteral(tipoToken)) || (isVariavel(tipoToken))){        //verifica por parametros validos
            gambs++;
        }
    }
    
    if (gambs == tableFuncProc[indFuction].contParametros){
        return 1;
    }
    else{
        printf("Erro. Numero de parametros passado eh insuficiente. \n");
        return 0;
    }    
}



//-------------------------------------------------------------------------------------------------------------------------------

/**
 * Funcao isFunction() verifica se o token atual esta presente na tabela de funcoes, caracterizando-se assim a 
 * chamada de uma function.
 * 
 * Retorna o indice da funcao se verdadeiro, ou -1 se falso
 */


int isFunction(){
    int i;
    
    for (i = 0; i < indTabela; i++){
        if (strcmp(tokenAtual, tableFuncProc[i].idFuncProc) == 0){
            //o token atual eh uma chamada de funcao
            return i;
        }    
    }
    return -1;
}

//-------------------------------------------------------------------------------------------------------------------------------
//Writeln
int checkWriteln(){
    int tipoToken;
    
    tipoToken = nexttoken();
    if (strcmp(tokenAtual, ";") != 0){
        printf("Erro. Era esperado um ; apos writeln");
        return 0;
    }
    return 1;
}

//-------------------------------------------------------------------------------------------------------------------------------
//Write
int checkWrite(){
    int tipoToken;
    char c;    
        
    c = ' ';
    while (c == ' ' || c == '\n'){
        c = lerChar();
    }
    
    if(c != '('){
     printf("Erro. O token ( era esperado apos write. \n");   
     return 0;
    }


    if (checkDeclWrite() != 1){
		return 0;
	}

	buffer.ind_buffer--;
	c = ' ';
    while (c == ' ' || c == '\n'){
        c = lerChar();
    }

    if(c != ')'){
     printf("Erro. O token ) era esperado apos a declaracao. \n");   
     return 0;
    }


	tipoToken = nexttoken();

	if ((strcmp(tokenAtual, ";") != 0)){
		printf("Erro. Era esperado ; apos o fecha parenteses");
		return 0;
	}
    
	printf("\nwrite funcionando");
	return 1;
}
//-------------------------------------------------------------------------------------------------------------------------------

int checkDeclWrite(){
	int tipoToken; 
	char c;

    tipoToken = nexttoken();
	printf("\ntoken: %s", tokenAtual);

	if (isVariavel(tipoToken) == 1){

	    c = ' ';
	    while (c == ' ' || c == '\n'){
        	c = lerChar();
    	}
		
		if ((c != ',') && (c != ')')){
			printf("Erro. Era esperado virgula ou fecha parenteses apos variavel");
			return 0;
		}
		else if(c == ',') {
			checkDeclWrite();
		}
		else if(c == ')'){
			return 1;
		}
	}
	else if(isLiteral(tipoToken) == 1){

	    c = ' ';
	    while (c == ' ' || c == '\n'){
        	c = lerChar();
    	}
		
		if ((c != ',') && (c != ')')){
			printf("Erro. Era esperado virgula ou fecha parenteses apos literal");
			return 0;
		}
		else if(c == ',') {
			checkDeclWrite();
		}
		else if(c == ')'){
			return 1;
		}
	}
}


//-------------------------------------------------------------------------------------------------------------------------------
//Read

int checkRead(){
    int tipoToken;
    char c;    
        
    c = ' ';
    while (c == ' ' || c == '\n'){ 
        c = lerChar();
    }
    
    if(c != '('){
     printf("Erro. O token ( era esperado apos read. \n");   
     return 0;
    }
    
    tipoToken = nexttoken();
    if(isVariavel(tipoToken) == 0){
        printf("Erro. Era esperado uma variavel apos o parenteses\n");
        return 0;
    }
    
    c = ' ';
    while(c == ' '){
        c = lerChar();
    }
    if(c != ')'){
        printf("Erro. Era esperado um ) apos a variavel");
        return 0;
    }
    
    tipoToken = nexttoken();
    if(strcmp(tokenAtual, ";") != 0){
        printf("Erro. Era esperado um ponto e virgula apos o fecha parenteses");
        return 0;
    }
    return 1;
}



//-------------------------------------------------------------------------------------------------------------------------------
//Procedimento


int checkDeclProcedure(){
    int tipoToken;
    
    //O ultimo token lido foi function, e o proximo token devera ser o id da funcao
    tipoToken = nexttoken();
    if (isVariavel(tipoToken) == 1){
        strcpy(tableFuncProc[indTabela].idFuncProc, tokenAtual);       //Insere o token atual, que eh o id da funcao
    }
    else{
        printf("Erro. Nao foi encontrado um ID valido para a function! \n");
        return 0;
    }
    
    //ID encontrado e inserido na tabela, comeca agora a busca pela lista de parametros
    //printf(" Caraleo %s \n\n\n", tokenAtual);
    
    char c;
    c = lerChar();
    if (c != '('){
        printf("Erro. O token ( era esperado, e nao foi encontrado. \n");
        return 0;
    }
    
    if (checkDeclParametros() == 0){
        printf("Erro. Declaracao de parametros invalida. \n");
        return 0;
    }
    
    c = ' ';
    while (c == ' '){
        c = lerChar();
    }
    if (c != ')'){
        printf("Erro. O token ) era esperado, e nao foi encontrado. \n");
        return 0;
    }
    
    //Buscando pelo token ;
    tipoToken = nexttoken();
    if (strcmp(tokenAtual, ";") != 0){
        printf("Erro. O token ; era esperado ao final da declaracao da funcao. \n");
    }

    tableFuncProc[indTabela].funcProc = 'f';
}


//------------------------------------------------------------------------------------------------------------------------------

/**
 *Funcao checkDeclFunction verifica a estrutura de uma declaracao de uma function.
 * Retorna 1 se verdadeiro, ou 0 se falso
 * 
 */
int checkDeclFunction(){
    int tipoToken;
    
    //O ultimo token lido foi function, e o proximo token devera ser o id da funcao
    tipoToken = nexttoken();
    if (isVariavel(tipoToken) == 1){
        strcpy(tableFuncProc[indTabela].idFuncProc, tokenAtual);       //Insere o token atual, que eh o id da funcao
    }
    else{
        printf("Erro. Nao foi encontrado um ID valido para a function! \n");
        return 0;
    }
    
    //ID encontrado e inserido na tabela, comeca agora a busca pela lista de parametros
    //printf(" Caraleo %s \n\n\n", tokenAtual);
    
    char c;
    c = lerChar();
    if (c != '('){
        printf("Erro. O token ( era esperado, e nao foi encontrado. \n");
        return 0;
    }
    
    if (checkDeclParametros() == 0){
        printf("Erro. Declaracao de parametros invalida. \n");
        return 0;
    }
    
    c = ' ';
    while (c == ' '){
        c = lerChar();
    }
    if (c != ')'){
        printf("Erro. O token ) era esperado, e nao foi encontrado. \n");
        return 0;
    }
    
    //Buscando pelo token :
    tipoToken = nexttoken();
    printf("TA: %s \n", tokenAtual);
    if (strcmp(tokenAtual, ":") != 0){
        printf("Erro. Era esperado o token : antes do tipo de retorno da funcao. \n");
        return 0;    
    }
    
    //buscando pelo tipo de retorno da funcao
    tipoToken = nexttoken();
    if (isTipoVariavel() == 1){
        if (strcmp(tokenAtual, "INTEGER") == 0){
                tableFuncProc[indTabela].tipoRetorno = 'i';
        }
        else if (strcmp(tokenAtual, "CHAR") == 0){
            tableFuncProc[indTabela].tipoRetorno = 'c';
        }
        else if (strcmp(tokenAtual, "STRING") == 0){
            tableFuncProc[indTabela].tipoRetorno = 's';
        }
        else if (strcmp(tokenAtual, "REAL") == 0){
            tableFuncProc[indTabela].tipoRetorno = 'r';
        }
        else if (strcmp(tokenAtual, "BOOLEAN") == 0){
            tableFuncProc[indTabela].tipoRetorno = 'b';
        }
        else {
            printf("Erro. Tipo do parametro invalido. \n");
            return 0;
        }
    
    }
    else {
        printf("Erro. O tipo de retorno da funcao eh invalido. \n");
        return 0;
    }
    
    //Buscando pelo token ;
    tipoToken = nexttoken();
    if (strcmp(tokenAtual, ";") != 0){
        printf("Erro. O token ; era esperado ao final da declaracao da funcao. \n");
    }

    tableFuncProc[indTabela].funcProc = 'f';
}


//----------------------------------------------------------------------------------------------------------------------------

/**
 * Funcao checkDeclParametros verifica a estrutura da declaracao dos parametros de uma function ou procedure, e insere
 * esses parametros na tabela de funcoes e parametros 
 */

int checkDeclParametros(){
    int tipoToken;
    char c;
    int indice = 0;
    
    tableFuncProc[indTabela].contParametros = 0;
    
    //O ultimo caractere lido foi o ( da function ou procedure, comeca agora a busca pelos parametros entres "( )"
    
   
    // ( encontrado, comeca agora a busca pelos parametros    
    
    tipoToken = nexttoken();
    printf("%s VAR \n", tokenAtual);
    if (strcmp(tokenAtual, "VAR") == 0){
        tableFuncProc[indTabela].parametros[indice].valRef = 'v';       //valor passado por referencia

        //buscando pelo id do parametro
        tipoToken = nexttoken();
        printf("%s X \n", tokenAtual);
        if (isVariavel(tipoToken) == 1){
            strcpy(tableFuncProc[indTabela].parametros[indice].idParametro, tokenAtual);    //insere o parametro na tabela de simbolos
            tableFuncProc[indTabela].contParametros++;
        }

    }
    else if (isVariavel(tipoToken) == 1){
        tableFuncProc[indTabela].parametros[indice].valRef = 'r';       //valor passado por valor
        strcpy(tableFuncProc[indTabela].parametros[indice].idParametro, tokenAtual);    //insere o parametro na tabela de simbolos
    }
    else{
        printf("Erro. Parametro passado para a funcao invalido. \n");
        return 0;
    }


    //Buscando pelo token :
    tipoToken = nexttoken();
    if (strcmp(tokenAtual, ":") != 0){
        printf("Erro. O token : era esperado antes do tipo do parametro. \n");
        return 0;
    }




    tipoToken = nexttoken();
    if (isTipoVariavel() == 1){
        if (strcmp(tokenAtual, "INTEGER") == 0){
            tableFuncProc[indTabela].parametros[indice].tipoParametro = 'i';
        }
        else if (strcmp(tokenAtual, "CHAR") == 0){
            tableFuncProc[indTabela].parametros[indice].tipoParametro = 'c';
        }
        else if (strcmp(tokenAtual, "STRING") == 0){
            tableFuncProc[indTabela].parametros[indice].tipoParametro = 's';
        }
        else if (strcmp(tokenAtual, "REAL") == 0){
            tableFuncProc[indTabela].parametros[indice].tipoParametro = 'r';
        }
        else if (strcmp(tokenAtual, "BOOLEAN") == 0){
            tableFuncProc[indTabela].parametros[indice].tipoParametro = 'b';
        }
        else {
            printf("Erro. Tipo do parametro invalido. \n");
            return 0;
        }

        //Buscando pelo token ;
        c = ' ';
        while (c == ' '){       //buscando pelo caractere ) ou inicio de algum token
            c = lerChar();      //ignorando os espacos
        }
        if (c != ')'){
            buffer.ind_buffer--;        //Nao encontrou ), e devera voltar o ponteiro do buffer para obter o proximo token
            tipoToken = nexttoken();
            if (strcmp(tokenAtual, ";") != 0){
                printf("Erro. o token ; era esperado apos o tipo do parametro. \n");
                return 0;
            }
            else {
                if (checkDeclParametros() == 0){
                    printf("Erro. Passagem de parametros invalida. \n");
                    return 0;
                } 
            } 
        }
        else if (c == ')'){
            buffer.ind_buffer--;
            return 1;
        }
    }
    else {
        printf("Erro. Era esperado um tipo de parametro. \n");
        return 0;
    }    
    return 1;
}


//------------------------------------------------------------------------------------------------------------------------------

int valorss(int tipoToken){
    if (tipoToken == 5 || tipoToken == 7 || tipoToken == 8){
        return 1;
    }
    return 0;
}

//------------------------------------------------------------------------------------------------------------------------------

int fator(int tipoToken){
    
    printf("Entrou fator \n");
    
    if (valorss(tipoToken) == 1 || tipoToken == 3){
        return 1;
    }
    printf("Erro. A expressao encontrada eh invalida 1. %s \n", tokenAtual);
    return 0;
}


//------------------------------------------------------------------------------------------------------------------------------

int termo(){
    int tipoToken;
    char c;
    
    printf("Entrou termo \n");
    
    tipoToken = nexttoken();
    printf("1 tokenAtual %s | tipoToken %d \n", tokenAtual, tipoToken);
    if (fator(tipoToken) != 1){
        printf("Erro. A expressao encontrada eh invalida 2. \n");
        return 0;
    }
    
    c = ' ';
    while (c == ' '){
        c = lerChar();
    }
    buffer.ind_buffer--;
    if (c == ')'){
        buffer.ind_buffer--;
        return 1;
    }
    
    //primeiro fator encontrado
    tipoToken = nexttoken();
    printf("2 tokenAtual %s | tipoToken %d \n", tokenAtual, tipoToken);
    if (isOperador(tipoToken) == 1){
        tipoToken = nexttoken();
        printf("3 tokenAtual %s | tipoToken %d \n", tokenAtual, tipoToken);
        if (fator(tipoToken) != 1){
            printf("Erro. A expressao econtrada eh invalida 3. \n");
            return 0;
        }
        
        //Buscando pelo opcomp
        tipoToken = nexttoken();
        printf("4 tokenAtual %s | tipoToken %d \n", tokenAtual, tipoToken);
        if (isOpcomp() != 1){
            printf("Erro. A expressao econtrada eh invalida 4. \n");
            return 0;
        }
        
        //Buscando pelo ultimo fator
        tipoToken = nexttoken();
        printf("5 tokenAtual %s | tipoToken %d \n", tokenAtual, tipoToken);
        if (fator(tipoToken) == 0){
            printf("Erro. A expressao econtrada eh invalida 5. \n");
            return 0;
        }
        
        return 1;
        
    }
    else if (isOpcomp() == 1){
        //Buscando pelo ultimo fator
        tipoToken = nexttoken();
        printf("6 tokenAtual %s | tipoToken %d \n", tokenAtual, tipoToken);
        if (fator(tipoToken) == 0){
            printf("Erro. A expressao econtrada eh invalida 6. \n");
            return 0;
        }
        
        return 1;
    }
    else{
        printf("Erro. A expressao encontrada eh invalida 7. \n");
        return 0;
    }
    return 1;

}


//------------------------------------------------------------------------------------------------------------------------------

int isOperador(int tipoToken){
    if ((strcmp(tokenAtual, "+") == 0) || (strcmp(tokenAtual, "-") == 0) || (strcmp(tokenAtual, "*") == 0) || (strcmp(tokenAtual, "/") == 0)){
        return 1;
    }
    return 0;
}

//------------------------------------------------------------------------------------------------------------------------------

int isOpcomp(){
    if (strcmp(tokenAtual, ">") == 0 || strcmp(tokenAtual, "<") == 0 || strcmp(tokenAtual, "<>") == 0 || 
    strcmp(tokenAtual, ">=") == 0 || strcmp(tokenAtual, "<=") == 0 || strcmp(tokenAtual, "=") == 0){
        return 1;
    }
    return 0;    
}

//------------------------------------------------------------------------------------------------------------------------------

int rec1(){
    int tipoToken;
    char c;
    
    printf("Entrou rec1 \n");
    
    c = ' ';
    while (c == ' '){
        c = lerChar();
    }
    buffer.ind_buffer--;
    if (c == ')'){        
        return 1;
    }
    
    tipoToken = nexttoken();
    printf("7 tokenAtual %s | tipoToken %d \n", tokenAtual, tipoToken);
    if (isOpbool() == 1){
        expressao();        
    }
    else {
        printf("Erro. A expressao encontrada eh invalida 8. \n");
        exit(0);
        return 0;
    }
    return 1;
}


//------------------------------------------------------------------------------------------------------------------------------

int expressao(){
    int tipoToken;
    char c;
    
    printf("Entrou expressao. \n");
    
    c = ' ';
    while (c == ' '){
        c = lerChar();
    }
    buffer.ind_buffer--;
    if (c == ')'){
        return 1;
    }
    
    if (termo() == 1){
        rec1();
    }
    else {
        printf("Erro. A expressao encontrada eh invalida 9. \n");
        return 0;
    }
    return 1;
}

//------------------------------------------------------------------------------------------------------------------------------

int isOpbool(){
    if ((strcmp(tokenAtual, "AND") == 0) || strcmp(tokenAtual, "OR") == 0){
        return 1;
    }
    return 0;
}

//------------------------------------------------------------------------------------------------------------------------------

int comando(){
    int tipoToken;
    
    if(strcmp(tokenAtual, "END") == 0){
        return 2;
    }
    
    //atribuicao
    else if (isVariavel(tipoToken) == 1){        //Verifica se o token atual eh uma variavel, para assim, chamar a funcao checkAtribuicao()
        checkAtribuicao();
    }

    //writeln
    else if(strcmp(tokenAtual, "WRITELN") == 0){
        if(checkWriteln() == 0){
            printf("Erro. Era esperado o token ; apos writeln mas nao foi encontrado. \n");
            return 0;
        }
    }
    
    //write
    else if(strcmp(tokenAtual, "WRITE") == 0){
        if(checkWrite() == 0){
            printf("Erro. Erro no comando WRITE \n");
            return 0;
        }
    }
    
    //read
    else if(strcmp(tokenAtual, "READ") == 0){
        if (checkRead() == 0){
            printf("Erro. Erro no comando READ \n");
            return 0;
        }
    }
    
    //while
    else if(strcmp(tokenAtual, "WHILE") == 0) {
        if (checkWhile() == 0){
            printf("Erro. Erro no bloco WHILE. \n");
            return 0;
        }
    }

    //if
    else if (strcmp(tokenAtual, "IF") == 0){
        if (checkIf() == 0){
            printf("Erro. Erro no bloco IF. \n");
            return 0;
        }
        
    }
           
    //function
    

    //procedure

    

}

//------------------------------------------------------------------------------------------------------------------------------

int checkIf(){
    int tipoToken;
    char c;
    
    c = ' ';
    while (c == ' '){
        c = lerChar();
    }
    if (c != '('){
        printf("Erro. O token ( era esperado apos IF, mas nao foi encontrado. \n");
        return 0;
    }
    
    //Buscando pela expressao
    tipoToken = nexttoken();
    if (expressao() == 0){
        printf("Erro. A condicao do bloco IF eh invalida. \n");
        return 0;
    }
    
    c = ' ';
    while (c == ' '){
        c = lerChar();
    }
    if (c != ')'){
        printf("Erro. O token ) era esperado apos IF, mas nao foi encontrado. \n");
        return 0;
    }
    
    tipoToken = nexttoken();
    if (strcmp(tokenAtual, "THEN") != 0){
        printf("Erro. O token THEN era esperado para abrir o bloco IF mas nao foi encontrado. \n");
        return 0;    
    }
    
    tipoToken = nexttoken();
    if (strcmp(tokenAtual, "BEGIN") != 0){
        printf("Erro. O token BEGIN era esperado para abrir o bloco IF mas nao foi encontrado. \n");
        return 0;    
    }
    
    //comandos
    tipoToken = nexttoken();
    while (comando() != 2){
        tipoToken = nexttoken();
    }    
    
    tipoToken = nexttoken();
    if (strcmp(tokenAtual, ";") != 0){
        printf("Erro. O token ; era esperado apos o fechamento do bloco IF mas nao foi encontrado. \n");
        return 0;
    }
            
    return 1;
    
    
}


//------------------------------------------------------------------------------------------------------------------------------


int checkWhile(){
    int tipoToken;
    char c;
    
    
    c = ' ';
    while (c == ' '){
        c = lerChar();
    }
    if (c != '('){
        printf("Erro. O token ( era esperado e nao foi encontrado. \n");
        return 0;    
    }
    
    tipoToken = nexttoken();
    if (expressao() == 0){
        printf("Erro. A expressao passada para o bloco while eh invalida. \n");
        return 0;
    }
    
    c = ' ';
    while (c == ' '){
        c = lerChar();
    }
    if (c != ')'){
        printf("Erro. O token ) era esperado e nao foi encontrado. \n");
        return 0;    
    }
    
    //Bucando o token DO
    tipoToken = nexttoken();
    if (strcmp(tokenAtual, "DO") != 0){
        printf("Erro. O token DO era esperado para iniciar o bloco WHILE, mas nao foi encontrado. \n");
        return 0;
    }
    
    //buscando o token BEGIN
    if (strcmp(tokenAtual, "BEGIN") != 0){
        printf("Erro. O token BEGIN era esperado para inciar o bloco WHILE, mas nao foi encontrado. \n");
        return 0;
    }
    
    //Comandos
    tipoToken = nexttoken();
    while (comando() != 2){
        tipoToken = nexttoken();
    }    
    
    tipoToken = nexttoken();
    if (strcmp(tokenAtual, ";") != 0){
        printf("Erro. O token ; era esperado apos o fechamento do bloco mas nao foi encontrado. \n");
        return 0;
    }
            
    return 1;  
}

//------------------------------------------------------------------------------------------------------------------------------